"""告警列表/详情"""

from fastapi import APIRouter, Depends, Path

from app.common.auth import check_permission
from app.common.common import DbDep, AuditLogDep, AlarmStatisticsServiceDep
from app.crud import alarm_crud
from app.schemas.alarm_schemas import (
	AlarmListRequest, AlarmListResponse,
	AlarmCloseRequest, AlarmAckResponse,
	AlarmCloseResponse, AlarmRuleListResponse,
	AlarmDetailResponse, AlarmBatchAckItem, AlarmBatchAckRequest, AlarmBatchAckResponse, AlarmTypeListResponse,
	RegionAlarmStatsResponse, RegionAlarmStatsRequest, AlarmTypeStatsResponse, AlarmTypeStatsRequest,
	AbnormalDeviceAlarmRequest, AbnormalDeviceAlarmResponse, AbnormalDeviceAlarmItem
)
from app.schemas.user_schemas import UserInDB
from common.base_enums import AlarmStatus
from common.exceptions import BizException, ErrorCode
from common.logger import create_logger
from common.response import ApiResponse

logger = create_logger(__name__)

router = APIRouter(prefix="/alarms", tags=["告警管理"])

# 检查是否具有告警管理权限
require_alarm_manage = check_permission("alarm:manage")
# 检查是否具有告警查看权限
require_alarm_view = check_permission("alarm:view")


@router.post("/list", response_model=ApiResponse[AlarmListResponse], summary="获取告警列表")
async def list_alarms(
		request: AlarmListRequest,
		db: DbDep,
		_: UserInDB = Depends(require_alarm_view)
) -> ApiResponse[AlarmListResponse]:
	"""
	分页获取告警列表
	- 可按状态和电表编码筛选
	- 支持分页
	"""
	total, items = await alarm_crud.get_alarm_list(db, request)
	return ApiResponse.success(AlarmListResponse(total=total, items=items))


@router.post("/batch/ack",
			 response_model=ApiResponse[AlarmBatchAckResponse],
			 summary="批量确认告警")
async def batch_ack_alarms(
		request: AlarmBatchAckRequest,
		db: DbDep, _audit: AuditLogDep,
		current_user: UserInDB = Depends(require_alarm_manage)
) -> ApiResponse[AlarmBatchAckResponse]:
	"""一次最多 100 条，返回成功/失败明细"""
	success, failed = [], []
	async with db.transaction():
		for aid in request.alarm_ids:
			alarm = await alarm_crud.get_alarm_by_id(db, aid)
			if not alarm or alarm.status != AlarmStatus.OPEN:
				failed.append(AlarmBatchAckItem(
					alarm_id=aid, status=alarm.status if alarm else AlarmStatus.CLOSED))
				continue

			await alarm_crud.update_alarm_status(db, aid, AlarmStatus.ACKED)
			await alarm_crud.insert_ack_log(db, aid, current_user.name, "ACK")
			success.append(AlarmBatchAckItem(alarm_id=aid, status=AlarmStatus.ACKED))

	return ApiResponse.success(
		AlarmBatchAckResponse(success=success, failed=failed))


@router.get("/rules", response_model=ApiResponse[AlarmRuleListResponse], summary="获取可用告警规则")
async def list_alarm_rules(
		db: DbDep,
		_: UserInDB = Depends(require_alarm_view)
) -> ApiResponse[AlarmRuleListResponse]:
	"""
	获取启用的告警规则列表
	"""
	rules = await alarm_crud.get_enabled_alarm_rules(db)
	return ApiResponse.success(AlarmRuleListResponse(items=rules))


@router.get("/types", response_model=ApiResponse[AlarmTypeListResponse], summary="获取告警类型列表")
async def get_alarm_types(
		db: DbDep,
		service: AlarmStatisticsServiceDep,
		_: UserInDB = Depends(require_alarm_view)
) -> ApiResponse[AlarmTypeListResponse]:
	"""
	获取系统中所有告警类型列表

	返回:
		告警类型列表，包含类型代码和名称
	"""
	result = await service.get_alarm_types(db)
	return ApiResponse.success(result)


@router.post("/region-stats", response_model=ApiResponse[RegionAlarmStatsResponse], summary="获取区域告警统计")
async def get_region_alarm_stats(
		db: DbDep,
		service: AlarmStatisticsServiceDep,
		request: RegionAlarmStatsRequest,
		_: UserInDB = Depends(require_alarm_view)
) -> ApiResponse[RegionAlarmStatsResponse]:
	"""
	根据区域代码、告警类型和时间周期查询下级区域告警事件统计
	返回:
		下级区域的告警统计数据，包含区域代码、区域名称和告警数量
	"""
	result = await service.get_region_alarm_stats(db, request)
	return ApiResponse.success(result)


@router.post("/type-stats", response_model=ApiResponse[AlarmTypeStatsResponse], summary="获取告警类型统计")
async def get_alarm_type_stats(
		db: DbDep,
		service: AlarmStatisticsServiceDep,
		request: AlarmTypeStatsRequest,
		_: UserInDB = Depends(require_alarm_view)
) -> ApiResponse[AlarmTypeStatsResponse]:
	"""
	根据区域代码、时间周期查询各告警类型的数量统计

	参数:
		- region_code: 区域代码
		- start_time: 开始时间
		- end_time: 结束时间
		- alarm_type: 告警类型（可选）
		- limit: 返回结果数量限制（可选）

	返回:
		各告警类型的统计数据，包含告警类型代码、名称和数量
	"""
	result = await service.get_alarm_type_stats(db, request)
	return ApiResponse.success(result)


@router.get("/{alarm_id}", response_model=ApiResponse[AlarmDetailResponse], summary="获取告警详情")
async def get_alarm_detail(
		db: DbDep,
		alarm_id: int = Path(..., description="告警ID"),
		_: UserInDB = Depends(require_alarm_view)
) -> ApiResponse[AlarmDetailResponse]:
	"""
	获取告警详情，包括时间线信息
	"""
	alarm_detail = await alarm_crud.get_alarm_detail(db, alarm_id)
	if not alarm_detail:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="告警不存在")
	return ApiResponse.success(alarm_detail)


@router.post("/{alarm_id}/ack", response_model=ApiResponse[AlarmAckResponse], summary="确认告警")
async def ack_alarm(
		db: DbDep,
		_audit: AuditLogDep,
		alarm_id: int = Path(..., description="告警ID"),
		current_user: UserInDB = Depends(require_alarm_manage)
) -> ApiResponse[AlarmAckResponse]:
	"""
	人工确认告警（OPEN → ACKED）
	"""
	# 检查告警是否存在
	alarm = await alarm_crud.get_alarm_by_id(db, alarm_id)
	if not alarm:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="告警不存在")

	# 检查状态是否允许确认
	if alarm.status != AlarmStatus.OPEN:
		raise BizException.from_error_code(ErrorCode.CONFLICT, message="告警状态不允许确认")

	# 更新状态
	success = await alarm_crud.update_alarm_status(db, alarm_id, AlarmStatus.ACKED)
	if not success:
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="确认告警失败")

	# 新增操作记录
	await alarm_crud.insert_ack_log(db, alarm_id, current_user.name, "ACK")

	# 重新获取告警信息
	updated_alarm = await alarm_crud.get_alarm_by_id(db, alarm_id)

	return ApiResponse.success(AlarmAckResponse(id=updated_alarm.id, status=updated_alarm.status))


@router.put("/{alarm_id}/close", response_model=ApiResponse[AlarmCloseResponse], summary="强制关闭告警")
async def close_alarm(
		db: DbDep,
		_audit: AuditLogDep,
		alarm_id: int = Path(..., description="告警ID"),
		request: AlarmCloseRequest = None,
		current_user: UserInDB = Depends(require_alarm_manage)
) -> ApiResponse[AlarmCloseResponse]:
	"""
	管理员强制关闭告警（CLOSED）
	"""
	# 检查告警是否存在
	alarm = await alarm_crud.get_alarm_by_id(db, alarm_id)
	if not alarm:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="告警不存在")

	# 幂等处理：如果已经是关闭状态，直接返回
	if alarm.status == AlarmStatus.CLOSED:
		return ApiResponse.success(AlarmCloseResponse(id=alarm.id, status=alarm.status))

	# 更新状态
	success = await alarm_crud.update_alarm_status(db, alarm_id, AlarmStatus.CLOSED, request.close_reason)
	if not success:
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="关闭告警失败")

	# 重新获取告警信息
	updated_alarm = await alarm_crud.get_alarm_by_id(db, alarm_id)

	# 新增操作记录
	await alarm_crud.insert_ack_log(db, alarm_id, current_user.name, "CLOSE")

	return ApiResponse.success(AlarmCloseResponse(id=updated_alarm.id, status=updated_alarm.status))


@router.post("/abnormal-devices", response_model=ApiResponse[AbnormalDeviceAlarmResponse],
			 summary="获取异常设备告警记录")
async def get_abnormal_device_alarms(
		db: DbDep,
		request: AbnormalDeviceAlarmRequest,
		_: UserInDB = Depends(require_alarm_view)
) -> ApiResponse[AbnormalDeviceAlarmResponse]:
	"""
	获取异常设备告警记录列表（分页）

	参数:
		- device_type: 设备类型 (METER/RTU/BOX)
		- station_id: 台区ID（可选）
		- start_time: 开始时间
		- end_time: 结束时间
		- page: 页码
		- size: 每页大小

	返回:
		告警记录列表，包含：
		- serial_no: 设备编号（am_alarm的meter_code）
		- alarm_type: 告警类型
		- raised_at: 告警产生时间
		- work_order_code: 工单编号
		- work_order_id: 工单ID
		- location_info: 位置信息
	"""
	try:
		# 验证设备类型
		valid_types = ['METER', 'RTU', 'BOX']
		if request.device_type not in valid_types:
			raise BizException.from_error_code(
				ErrorCode.BAD_REQUEST,
				message=f"无效的设备类型，必须是 {', '.join(valid_types)} 之一"
			)

		# 查询异常设备告警记录
		total, abnormal_total, rows = await alarm_crud.get_abnormal_device_alarms(
			db,
			request.device_type,
			request.station_id,
			request.start_time,
			request.end_time,
			request.page,
			request.size
		)

		# 构建响应，处理地址信息
		items = []
		for row in rows:
			# 提取地址信息字段
			location_info = []
			if row.get('address_id'):
				location_info.append({
					"address_id": row.get('address_id'),
					"address_name": row.get('address_name'),
					"full_address": row.get('full_address'),
					"longitude": row.get('longitude'),
					"latitude": row.get('latitude'),
					"address_type": row.get('address_type'),
					"is_primary": bool(row.get('is_primary'))
				})

			# 构建告警项
			item = AbnormalDeviceAlarmItem(
				device_id=row.get('device_id'),
				serial_no=row['serial_no'],
				alarm_type=row['alarm_type'],
				raised_at=row['raised_at'],
				work_order_code=row.get('work_order_code'),
				work_order_id=row.get('work_order_id'),
				location_info=location_info
			)
			items.append(item)

		pages = (total + request.size - 1) // request.size

		response = AbnormalDeviceAlarmResponse(
			total=total,
			abnormal_total=abnormal_total,
			items=items,
			page=request.page,
			size=request.size,
			pages=pages,
			has_next=request.page * request.size < total,
			has_prev=request.page > 1
		)

		return ApiResponse.success(response, f"查询成功，返回 {len(items)} 条记录")
	except BizException as e:
		raise e
	except Exception as e:
		logger.error(f"查询异常设备告警记录失败: {e}")
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="查询失败")
